#ifndef _LINKED_LINK_H
#define _LINKED_LINK_H
#include "utils.h"
/* Definitions for abstract linked_list. */

typedef struct linked_list_data_t *linked_list_t;

typedef void *linked_list_element_t;

typedef int (linked_list_pfcompare_t)(linked_list_element_t, linked_list_element_t);
//typedef int boolean_t;

#ifndef FALSE
#define FALSE 0
#define TRUE (!FALSE)
#endif // FALSE

/*
 * Creates and returns a new linked_list.
 * Returns null on failure, else a valid linked_list.
 */
extern linked_list_t linked_list_create();

/*
 * Appends an element to the end of the linked_list.
 */
extern void linked_list_append(linked_list_t l, linked_list_element_t k, linked_list_element_t e);

/* Remove the an element from the linked_list with the matches the given key
 *   Returns false if isEmpty() prior to remove or not found.
 */
extern boolean_t linked_list_remove(linked_list_t l, linked_list_element_t k);

/*
 * Returns TRUE if linked_list is empty. FALSE otherwise.
 */
extern boolean_t linked_list_is_empty(linked_list_t l);

/*
 * Returns number of elements in the linked_list.
 */
extern int linked_list_size(linked_list_t l);

/*
 *Searh for a given key
 */
extern linked_list_element_t  linked_list_key_search(linked_list_t l, linked_list_element_t k);


/*
 * Function Application.
 *
 * Applies the given function to each element of the linked_list. Given closure
 * is also provided to the function. Given function should
 * return TRUE if iteration should continue.
 * 
 * Returns isEmpty().
 *
 * Behaviour is undefined if the state of the linked_list changes during the application.
 *
 * Sample client use:
 *

	int count_elements(linked_list_element_t e, linked_list_pfapply_closure_t c)
	{
	     int *x = (int*)c;
	     *x = *x + 1;
	     return TRUE;
        }

	void bar()
	{
	    int x = 0;
	    linked_list_t l = linked_list_new();
	    if (!l) error();
	    for (int i = 0; i < 10; i++) {   
	        linked_list_append(l, l);
            }
	    linked_list_apply(l, count_elements, &x);
	    printf("linked_list size is %d\n", x);
	}
*/
	    


typedef void *linked_list_pfapply_closure_t;
typedef boolean_t (linked_list_pfapply_t)(linked_list_element_t,linked_list_element_t, linked_list_pfapply_closure_t);

extern boolean_t linked_list_apply(linked_list_t l, linked_list_pfapply_t pf, linked_list_pfapply_closure_t cl);


/* THESE FUNCTIONS ARE NOT IMPLEMENTED */

/*
 * Reverses the elements on the linked_list in place.
 */

extern void linked_list_reverse(linked_list_t l);


/*
 * Sorts the elements in the linked_list in place.
 * Relies on provided compare function, which returns:
 *	-1:   e1 < e2
 *	 0:   e1 == e2
 *	 1:   e1 > e2
 */


extern void linked_list_sort(linked_list_t l, linked_list_pfcompare_t pf);


#endif //_LINKED_LINK_H


